package com.wwj.aicodemother.core;

import cn.hutool.json.JSONUtil;
import com.wwj.aicodemother.AI.AiCodeGeneratorService;
import com.wwj.aicodemother.AI.AiCodeGeneratorServiceFactory;
import com.wwj.aicodemother.AI.model.HtmlCodeResult;
import com.wwj.aicodemother.AI.model.MultiFileCodeResult;
import com.wwj.aicodemother.AI.model.message.AiResponseMessage;
import com.wwj.aicodemother.AI.model.message.ToolExecutedMessage;
import com.wwj.aicodemother.AI.model.message.ToolRequestMessage;
import com.wwj.aicodemother.constant.AppConstant;
import com.wwj.aicodemother.core.builder.VueProjectBuilder;
import com.wwj.aicodemother.core.parser.CodeParserExecutor;
import com.wwj.aicodemother.core.saver.CodeFileSaverExecutor;
import com.wwj.aicodemother.exception.BusinessException;
import com.wwj.aicodemother.exception.ErrorCode;
import com.wwj.aicodemother.model.enums.CodeGenTypeEnum;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.service.TokenStream;
import dev.langchain4j.service.tool.ToolExecution;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.io.File;

/**
 * Ai 生成代码门面类，组合代码生成和保存功能
 */
@Service
@Slf4j
public class AiCodeGeneratorFacade {

    @Resource
    private AiCodeGeneratorServiceFactory aiCodeGeneratorServiceFactory;

    @Resource
    private VueProjectBuilder  vueProjectBuilder;
    /**
     * 统一入口，根据类型生成并保存代码
     *
     * @param userMessage
     * @param codeGenTypeEnum
     * @param appId           应用ID
     * @return
     */
    public File generateAndSaveCode(String userMessage, CodeGenTypeEnum codeGenTypeEnum, Long appId) {
        if (codeGenTypeEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "生成类型不能为空");
        }
        //根据 appId 获取相应的 AI服务实例
        AiCodeGeneratorService aiCodeGeneratorService = aiCodeGeneratorServiceFactory.getAiCodeGeneratorService(appId, codeGenTypeEnum);
        return switch (codeGenTypeEnum) {
            case HTML -> {
                HtmlCodeResult htmlCodeResult = aiCodeGeneratorService.generateHtmlCode(userMessage);
                yield CodeFileSaverExecutor.executeSaver(htmlCodeResult, codeGenTypeEnum, appId);
            }
            case MULTI_FILE -> {
                MultiFileCodeResult multiFileCodeResult = aiCodeGeneratorService.generateMultiFileCode(userMessage);
                yield CodeFileSaverExecutor.executeSaver(multiFileCodeResult, codeGenTypeEnum, appId);
            }
            default -> {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "生成类型错误");
            }
        };
    }

    /**
     * 统一入口，根据类型生成并保存代码(流式)
     *
     * @param userMessage
     * @param codeGenTypeEnum
     * @param appId           应用ID
     * @return
     */
    public Flux<String> generateAndSaveCodeStream(String userMessage, CodeGenTypeEnum codeGenTypeEnum, Long appId) {
        if (codeGenTypeEnum == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "生成类型不能为空");
        }
        //根据 appId 获取相应的 AI服务实例
        AiCodeGeneratorService aiCodeGeneratorService = aiCodeGeneratorServiceFactory.getAiCodeGeneratorService(appId, codeGenTypeEnum);
        return switch (codeGenTypeEnum) {
            case HTML -> {
                Flux<String> codeStream = aiCodeGeneratorService.generateHtmlCodeStream(userMessage);
                yield processCodeStream(codeStream, CodeGenTypeEnum.HTML, appId);
            }
            case MULTI_FILE -> {
                Flux<String> codeStream = aiCodeGeneratorService.generateMultiFileCodeStream(userMessage);
                yield processCodeStream(codeStream, CodeGenTypeEnum.MULTI_FILE, appId);
            }
            case VUE_PROJECT -> {
                TokenStream tokenStream = aiCodeGeneratorService.generateVueProjectCodeStream(appId, userMessage);
                yield processTokenStream(tokenStream,appId);
            }
            default -> {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "生成类型错误");
            }
        };
    }

    /**
     * 转换TokenStream为Flux<String>
     *
     * @param tokenStream
     * @param appId
     * @return
     */
    private Flux<String> processTokenStream(TokenStream tokenStream, Long appId) {
        return Flux.create(sink -> {
            tokenStream.onPartialResponse((String partialresponse) -> {
                        AiResponseMessage aiResponseMessage = new AiResponseMessage(partialresponse);
                        sink.next(JSONUtil.toJsonStr(aiResponseMessage));
                    })
                    .onPartialToolExecutionRequest((index, toolExecutionRequest) -> {
                        ToolRequestMessage toolRequestMessage = new ToolRequestMessage(toolExecutionRequest);
                        sink.next(JSONUtil.toJsonStr(toolRequestMessage));
                    })
                    .onToolExecuted((ToolExecution ToolExecution) -> {
                        ToolExecutedMessage toolExecutedMessage = new ToolExecutedMessage(ToolExecution);
                        sink.next(JSONUtil.toJsonStr(toolExecutedMessage));
                    })
                    .onCompleteResponse((ChatResponse response) -> {
                        // 执行 Vue 项目构建（同步执行，确保预览时项目已就绪）
                        String projectPath = AppConstant.CODE_OUTPUT_ROOT_DIR + File.separator + "vue_project_" + appId;
                        vueProjectBuilder.buildProject(projectPath);
                        sink.complete();
                    })
                    .onError((Throwable error) -> {
                        error.printStackTrace();
                        sink.error(error);
                    })
                    .start();
        });
    }


    /**
     * 通用生成并保存多文件代码(流式)
     *
     * @param codeStream      代码流
     * @param codeGenTypeEnum 代码生成类型
     * @param appId           应用ID
     * @return Flux<String>
     */
    private Flux<String> processCodeStream(Flux<String> codeStream, CodeGenTypeEnum codeGenTypeEnum, Long appId) {
        //定义一个字符串拼接器，用于流式返回所有的代码之后保存代码
        StringBuilder codeBuilder = new StringBuilder();
        return codeStream.doOnNext(chunk -> {
            //实时收集代码片段
            codeBuilder.append(chunk);
        }).doOnComplete(() -> {
            try {
                //所有代码片段收集完毕，并解析
                String completeCode = codeBuilder.toString();
                // 解析代码为对象
                Object parsedResult = CodeParserExecutor.executeParser(completeCode, codeGenTypeEnum);
                // 使用执行器保存代码到文件
                File saveDir = CodeFileSaverExecutor.executeSaver(parsedResult, codeGenTypeEnum, appId);
                log.info("代码保存成功，保存路径为:{}", saveDir.getAbsolutePath());
            } catch (Exception e) {
                log.error("保存失败:{}", e.getMessage());
            }
        });
    }


}
